/**************************************************************************
** Qt Creator license header template
**   Special keywords: Programmer 2012/6/1 2012
**   Environment variables: 
**   To protect a percent sign, use '%'.
**************************************************************************/

#ifndef CONNECTEDCOMPONENT_H
#define CONNECTEDCOMPONENT_H


#include <vcg/complex/algorithms/clean.h>
#include <vcg/complex/algorithms/update/topology.h>
#include "subset.h"
#include <wrap/callback.h>


template<class MeshType,class MeshModelType>
class ConnectedComponent
{

public:
    typedef typename MeshType::VertexType            VertexType;
    typedef typename MeshType::VertexPointer         VertexPointer;
    typedef typename MeshType::VertexIterator        VertexIterator;
    typedef typename MeshType::ConstVertexIterator   ConstVertexIterator;
    typedef typename MeshType::EdgeIterator          EdgeIterator;
    typedef typename MeshType::EdgePointer           EdgePointer;
    typedef	typename MeshType::ScalarType		     ScalarType;
    typedef typename MeshType::FaceType              FaceType;
    typedef typename MeshType::FacePointer           FacePointer;
    typedef typename MeshType::FaceIterator          FaceIterator;
    typedef typename MeshType::ConstFaceIterator     ConstFaceIterator;
    typedef typename MeshType::FaceContainer         FaceContainer;

    ConnectedComponent(){}

    //split the mesh and add the splitted connected components as an individual mesh to the meshdoc
    static void SplitMesh( MeshModelType* pMM, CLightWeight_Tool* pLwt, vcg::CallBackPos* cb)
	{
		MeshType& m = pMM->cm;
        m.face.EnableFFAdjacency();							//reallocator the FF Adjacent memory
        vcg::tri::UpdateTopology<MeshType>::FaceFace(m);	//Calculate the FF topology data

        int numComponent = vcg::tri::Clean<MeshType>::CountConnectedComponents(m);		//statistic the components Number
        if(numComponent <= 1)
		{
            if(cb)
                cb(0,"number of component in the mesh is one, nothing happens");
    
            return;
        }

        FaceIterator fi;
        FacePointer fp;
        std::vector<FacePointer> subsetFaces;

        for(fi = m.face.begin();fi!= m.face.end();++fi)
            (*fi).ClearS();						//Un-selected all the faces

        int compNum = 0;
        std::stack<FacePointer> sf;
        FacePointer fpt = &*(m.face.begin());
        for(fi=m.face.begin();fi!=m.face.end();++fi)		//for each face to proceed
		{
            if(!(*fi).IsD() && !(*fi).IsS())				//if is not deleted and selected
			{
                subsetFaces.clear();						//clear subset
                (*fi).SetS();								//select the face
                sf.push(&*fi);								//push to stack
                while(!sf.empty())							//
				{											//
                    fpt = sf.top();							//top of the stack
                    subsetFaces.push_back(fpt);				//record to subsetFaces
                    sf.pop();								//pop of stack
                    for(int j =0;j<3;++j)					//for each the edge
					{	
                        if(!vcg::face::IsBorder(*fpt,j))	//if edge j is not the border
						{
                            fp = fpt->FFp(j);				//the j th adjacent face pointer
                            if(!(*fp).IsS())				//if not selected
							{
                                (*fp).SetS();				//select the face
                                sf.push(fp);				//add new face to the stack
                            }
                        }
                    }
                }
                compNum++;									//component number ++		

                MeshModelType* mmNew = pLwt->AddNewModel( "", "" );
				mmNew->UpdateDataMask( pMM );
                vcg::tri::SubSet<MeshType,std::vector<FacePointer> >( mmNew->cm,subsetFaces );
                //to be continued...

            }
        } //end for fi

        m.face.DisableFFAdjacency();
    }
};

#endif // CONNECTEDCOMPONENT_H
